<template>
  <div class="app-container">
    <div class="search-container">
      <el-form ref="queryFormRef" :model="queryParams" :inline="true">
        <el-form-item prop="name" label="名称">
          <el-input
            v-model="queryParams.name"
            placeholder="角色名称"
            @keyup.enter="handleQuery"
          />
        </el-form-item>

        <el-form-item>
          <el-button type="primary" @click="handleQuery"
            ><i-ep-search />搜索</el-button
          >
          <el-button @click="resetQuery"><i-ep-refresh />重置</el-button>
        </el-form-item>
      </el-form>
    </div>
    <el-row class="table-container" :gutter="5">
      <el-col :span="18">
        <el-card shadow="never" style="height: 100%">
          <template #header>
            <el-button
              type="success"
              v-hasPerm="['sys:role:add']"
              @click="openDialog(null, 1)"
              ><i-ep-plus />新增</el-button
            >
            <el-button
              type="danger"
              :disabled="ids.length === 0"
              v-hasPerm="['sys:role:del']"
              @click="handleDelete()"
              ><i-ep-delete />删除</el-button
            >
          </template>

          <el-table
            ref="dataTableRef"
            v-loading="loading"
            :data="roleList"
            class="fix-item"
            style="--fix-top-height: 185px"
            highlight-current-row
            row-key="id"
            @cell-click="handleClickRow"
            @selection-change="selectionChange"
          >
            <el-table-column type="selection" width="55" align="center" />
            <el-table-column
              prop="data.name"
              label="角色名称"
              :show-overflow-tooltip="true"
            />

            <el-table-column
              :show-overflow-tooltip="true"
              prop="data.remark"
              label="描述"
            />

            <el-table-column fixed="right" label="操作" width="220">
              <template #default="scope">
                <el-button
                  v-hasPerm="['sys:role:add']"
                  type="primary"
                  size="small"
                  link
                  @click="openDialog(scope.row.data, 1)"
                >
                  <i-ep-position />新增
                </el-button>
                <el-button
                  v-hasPerm="['sys:role:edit']"
                  type="primary"
                  size="small"
                  link
                  @click="openDialog(scope.row.data, 0)"
                >
                  <i-ep-edit />编辑
                </el-button>
                <el-button
                  v-hasPerm="['sys:role:del']"
                  type="primary"
                  size="small"
                  link
                  @click="handleDelete(scope.row.id)"
                >
                  <i-ep-delete />删除
                </el-button>
              </template>
            </el-table-column>
          </el-table>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card
          shadow="never"
          class="table-container flex-column role-menu"
          style="height: 100%"
        >
          <el-tabs v-model="activeName">
            <el-tab-pane label="菜单分配" name="first">
              <div class="menu-btn">
                <el-button
                  type="success"
                  size="small"
                  @click="handleRoleMenuSubmit"
                >
                  <i-ep-plus />保存
                </el-button>
              </div>

              <div class="fix-panel">
                <el-tree
                  ref="menuRef"
                  v-loading="menuLoading"
                  style="max-width: 600px; height: 100%; overflow-y: auto"
                  class="fix-panel"
                  :data="menuList"
                  show-checkbox
                  default-expand-all
                  node-key="id"
                  :props="defaultProps"
                />
              </div>
            </el-tab-pane>
            <el-tab-pane label="角色用户" name="second">
              <div class="fix-panel">
                <el-table
                  v-loading="menuLoading"
                  :data="userList"
                  height="100%"
                >
                  <el-table-column type="index" label="序号" width="80" />
                  <el-table-column prop="name" label="姓名" />
                  <el-table-column prop="account" label="账号" />
                  <!-- <el-table-column prop="status" label="状态" width="50">
                  <template #default="scope">
                    <div v-for="item in dict.userStatus" :key="item.code">
                      <span v-if="item.code == scope.row.status">
                        {{ item.name }}
                      </span>
                    </div>
                  </template>
                </el-table-column> -->
                </el-table>
              </div>
            </el-tab-pane>
          </el-tabs>
        </el-card>
      </el-col>
    </el-row>
    <!-- 角色表单弹窗 -->
    <el-dialog
      v-model="dialog.visible"
      :title="dialog.title"
      width="500px"
      draggable
      @close="closeDialog"
    >
      <el-form
        ref="roleFormRef"
        :model="formData"
        :rules="rules"
        label-width="100px"
      >
        <el-form-item label="上级角色" prop="pid">
          <el-tree-select
            v-model="formData.pid"
            placeholder="选择上级角色"
            :data="roleList"
            :props="props"
            node-key="id"
            filterable
            check-strictly
            default-expand-all
            :render-after-expand="false"
          />
        </el-form-item>

        <el-form-item label="角色名称" prop="name">
          <el-input
            v-model="formData.name"
            placeholder="请输入角色名称"
            maxlength="100"
          />
        </el-form-item>

        <el-form-item label="数据权限" prop="dataScope">
          <el-select v-model="formData.dataScope">
            <el-option key="0" label="全部数据" value="0" />
            <el-option key="1" label="部门及子部门数据" value="1" />
            <el-option key="2" label="本部门数据" value="2" />
            <el-option key="3" label="本人数据" value="3" />
          </el-select>
        </el-form-item>

        <el-form-item label="描述" prop="remark">
          <el-input
            v-model="formData.remark"
            type="textarea"
            placeholder="描述"
            maxlength="200"
            :autosize="{ minRows: 2, maxRows: 4 }"
          />
        </el-form-item>
      </el-form>

      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="handleSubmit">确 定</el-button>
          <el-button @click="closeDialog">取 消</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import {
  getRoleList,
  saveRole,
  deleteRoles,
  getRoleMenuIds,
  updateRoleMenus,
  getRoleUserInfo,
} from "@/api/role";
import { getMenuOptions } from "@/api/menu";
import { filterTree } from "@/utils/tree";
import { RolePageVO, RoleForm, RoleQuery } from "@/api/role/types";
import { UserPageVO } from "@/api/user/types";
import { MenuForm } from "@/api/menu/types";

defineOptions({
  name: "Role",
  inheritAttrs: false,
});

const activeName = ref("first");
const queryFormRef = ref(ElForm);
const roleFormRef = ref(ElForm);
const menuRef = ref(ElTree);

const loading = ref(false);
const menuLoading = ref(false);
const ids = ref<string[]>([]);

const defaultProps = {
  children: "children",
  label: "name",
};

const queryParams = reactive<RoleQuery>({
  name: "",
});

const roleList = ref<TreeResult<RolePageVO>[]>();
const userList = ref<UserPageVO[]>();

const props = {
  label: "name",
  children: "children",
};

const dialog = reactive({
  title: "",
  visible: false,
});

const formData = reactive<RoleForm>({
  name: "",
  dataScope: "1",
  remark: "",
});

const rules = reactive({
  name: [{ required: true, message: "请输入角色名称", trigger: "blur" }],
  dataScope: [{ required: true, message: "请选择数据权限", trigger: "blur" }],
});

const menuList = ref<TreeResult<MenuForm>[]>([]);

interface CheckedRole {
  id?: string;
  name?: string;
}
let checkedRole: CheckedRole = reactive({});

/** 查询 */
function handleQuery() {
  loading.value = true;
  getRoleList()
    .then(({ data }) => {
      roleList.value = filterNode(data);
    })
    .finally(() => {
      loading.value = false;
    });
}
/** 查询前端过滤 */
function filterNode(data: TreeResult<RolePageVO>[]): any {
  let name = queryParams.name;
  if (name) {
    return filterTree(data, "name", name);
  }

  return data;
}
/** 重置查询 */
function resetQuery() {
  queryFormRef.value.resetFields();
  handleQuery();
}

/** 打开角色表单弹窗 */
function openDialog(data: RoleForm, addOrEdit: any) {
  dialog.visible = true;
  if (addOrEdit) {
    dialog.title = "新增角色";
    let id = null;
    if (data) {
      id = data.id;
    }
    // 树的新增，设置上级编号为当前选中行
    resetForm(id);
  } else {
    dialog.title = "修改角色";
    Object.assign(formData, data);
  }
}

/** 角色保存提交 */
function handleSubmit() {
  roleFormRef.value.validate((valid: any) => {
    if (valid) {
      loading.value = true;
      const roleId = formData.id;
      saveRole(formData)
        .then(() => {
          if (roleId) {
            ElMessage.success("修改成功");
          } else {
            ElMessage.success("新增成功");
          }
          closeDialog();
          resetQuery();
        })
        .finally(() => (loading.value = false));
    }
  });
}

/** 关闭表单弹窗 */
function closeDialog() {
  dialog.visible = false;
  resetForm(null);
}

/** 重置表单 */
function resetForm(pid) {
  roleFormRef.value.resetFields && roleFormRef.value.resetFields();
  roleFormRef.value.clearValidate && roleFormRef.value.clearValidate();

  formData.pid = pid || "0";
  formData.dataScope = "";
  formData.name = "";
  formData.remark = "";
  formData.id = undefined;
}

/** 删除角色 */
function handleDelete(roleId?: string) {
  const roleIds = roleId ? [roleId] : ids.value;
  if (!roleIds) {
    ElMessage.warning("请勾选删除项");
    return;
  }

  ElMessageBox.confirm("确认删除已选中的数据项?", "警告", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning",
  }).then(() => {
    loading.value = true;
    deleteRoles(roleIds)
      .then(() => {
        ElMessage.success("删除成功");
        resetQuery();
      })
      .finally(() => (loading.value = false));
  });
}

/** 获取所有菜单 */
function listAllMenu() {
  const param = { type: "0" };
  // 获取所有的菜单, 按钮不要
  getMenuOptions(param).then((response) => {
    menuList.value = response.data;
  });
}

/** 行点击事件 */
function handleClickRow(row: RolePageVO) {
  getMenuIds(row);
  listUserInfoByRoleId(row);
}

/** 获取角色拥有的分配菜单 */
function getMenuIds(row: RolePageVO) {
  const roleId = row.id;
  checkedRole.id = roleId;
  if (roleId) {
    menuLoading.value = true;
    menuRef.value.setCheckedKeys([]);
    // 回显角色已拥有的菜单
    getRoleMenuIds(roleId)
      .then(({ data }) => {
        const checkedMenuIds = data;
        checkedMenuIds.forEach((it) => {
          menuRef.value.setChecked(it, true, false);
        });
      })
      .finally(() => {
        menuLoading.value = false;
      });
  }
}

/** 选中事件 */
function selectionChange(selection) {
  let arr = [];
  selection.forEach((it) => {
    arr.push(it.data.id);
  });
  ids.value = arr;
}

/** 角色分配菜单保存提交 */
function handleRoleMenuSubmit() {
  const roleId = checkedRole.id;
  if (roleId) {
    const checkedMenuIds: string[] = menuRef.value
      .getCheckedNodes(false, true)
      .map((node: any) => node.id);
    menuLoading.value = true;
    updateRoleMenus(roleId, checkedMenuIds)
      .then(() => {
        ElMessage.success("分配权限成功");
        resetQuery();
      })
      .finally(() => {
        menuLoading.value = false;
      });
  }
}

/** 查询角色拥有的用户 */
function listUserInfoByRoleId(row: any) {
  const roleId = row.id;
  if (roleId) {
    getRoleUserInfo(roleId).then(({ data }) => {
      userList.value = data;
    });
  }
}

onMounted(() => {
  handleQuery();
  listAllMenu();
});
</script>

<style lang="scss" scoped>
.role-menu {
  .menu-btn {
    position: absolute;
    top: 10px;
    right: 10px;
    z-index: 1;
  }
}

$varTopPanel: 192px;

.fix-panel {
  height: calc(100vh - $navbar-height - $varTopPanel);
}

.hasTagsView {
  .fix-panel {
    height: calc(100vh - $navbar-height - $tags-view-height - $varTopPanel);
  }
}
</style>
